home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xconq / X11.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  45KB  |  1,495 lines

  1. /* Copyright (c) 1987, 1988  Stanley T. Shebs, University of Utah. */
  2. /* Copyright 1988 by Chris D. Peterson, MIT. */
  3. /* Many improvements by Tim Moore, University of Utah. */
  4. /* This program may be used, copied, modified, and redistributed freely */
  5. /* for noncommercial purposes, so long as this notice remains intact.  */
  6.  
  7. #pragma comment(exestr, "@(#) X11.c 12.1 95/05/09 ")
  8.  
  9. /* RCS $Header: X11.c,v 1.3 88/07/19 11:10:03 shebs Exp $ */
  10.  
  11. /* Interface implementations for the X11 version of xconq. */
  12.  
  13. #include "config.h"
  14. #include "misc.h"
  15. #include "period.h"
  16. #include "side.h"
  17. #include "unit.h"
  18. #include "map.h"
  19. #include "global.h"
  20.  
  21. /* careful of the path of the X header files. */
  22.  
  23. #ifdef UNIX
  24. #include <signal.h>   /* needed for ^C disabling */
  25. #include <X11/Xlib.h>
  26. #include <X11/Xutil.h>
  27. #endif /* UNIX */
  28.  
  29. /* various bitmap definitions. */
  30.  
  31. #define dots_width 16
  32. #define dots_height 16
  33. static char dots_bits[] = {
  34.    0x01, 0x01,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  35.    0x10, 0x10,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  36.    0x01, 0x01,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  37.    0x10, 0x10,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
  38.  
  39. #define mask_width 16
  40. #define mask_height 16
  41. static char mask_bits[] = {
  42.    0xe0, 0x03,  0xd8, 0x0f,  0xb4, 0x19,  0x8a, 0x21, 
  43.    0x86, 0x61,  0x85, 0x41,  0x83, 0xc1,  0xff, 0xff, 
  44.    0xff, 0xff,  0x83, 0xc1,  0x82, 0xa1,  0x86, 0x61, 
  45.    0x84, 0x51,  0x98, 0x2d,  0xf0, 0x1b,  0xc0, 0x07};
  46.  
  47. #define curs_width 16
  48. #define curs_height 16
  49. static char curs_bits[] = {
  50.    0xe0, 0x03,  0x98, 0x0c,  0x84, 0x10,  0x82, 0x20, 
  51.    0x82, 0x20,  0x81, 0x40,  0x81, 0x40,  0xff, 0x7f, 
  52.    0x81, 0x40,  0x81, 0x40,  0x82, 0x20,  0x82, 0x20, 
  53.    0x84, 0x10,  0x98, 0x0c,  0xe0, 0x03,  0x00, 0x00};
  54.  
  55. #define bomb1_width 32
  56. #define bomb1_height 32
  57. static char bomb1_bits[] = {
  58.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  59.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  60.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  61.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  62.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  63.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  64.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  65.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  66.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  67.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  68.    0x00, 0xc0,  0x01, 0x00,  0x00, 0xf0,  0x07, 0x00, 
  69.    0x00, 0xf0,  0x07, 0x00,  0x00, 0xf8,  0x0f, 0x00, 
  70.    0x00, 0xf8,  0x0f, 0x00,  0x00, 0xfc,  0x0f, 0x00, 
  71.    0x00, 0xfe,  0x1f, 0x00,  0x00, 0xfe,  0x3f, 0x00, 
  72.    0x00, 0xfe,  0x3f, 0x00,  0x00, 0xfc,  0x1f, 0x00, 
  73.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
  74.  
  75. #define bomb2_width 32
  76. #define bomb2_height 32
  77. static char bomb2_bits[] = {
  78.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  79.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  80.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  81.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  82.    0x00, 0x00,  0x00, 0x00,  0x00, 0xf8,  0x01, 0x00, 
  83.    0x00, 0xf8,  0x07, 0x00,  0x00, 0xfc,  0x0f, 0x00, 
  84.    0x00, 0xfc,  0x1f, 0x00,  0x00, 0xfe,  0x1f, 0x00, 
  85.    0x00, 0xfe,  0x3f, 0x00,  0x00, 0xfc,  0x1f, 0x00, 
  86.    0x00, 0xfc,  0x0f, 0x00,  0x00, 0xf0,  0x07, 0x00, 
  87.    0x00, 0xf0,  0x03, 0x00,  0x00, 0xe0,  0x03, 0x00, 
  88.    0x00, 0xf0,  0x07, 0x00,  0x00, 0xf0,  0x07, 0x00, 
  89.    0x00, 0xf0,  0x0f, 0x00,  0x00, 0xf0,  0x0f, 0x00, 
  90.    0x00, 0xf8,  0x0f, 0x00,  0x00, 0xf8,  0x1f, 0x00, 
  91.    0x00, 0xf8,  0x1f, 0x00,  0x00, 0xfc,  0x1f, 0x00, 
  92.    0x00, 0xff,  0x7f, 0x00,  0xc0, 0xff,  0xff, 0x03, 
  93.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
  94.  
  95. #define bomb3_width 32
  96. #define bomb3_height 32
  97. static char bomb3_bits[] = {
  98.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  99.    0x00, 0x00,  0x00, 0x00,  0xfe, 0xe2,  0xa3, 0x3f, 
  100.    0x00, 0xfc,  0x1f, 0x00,  0x3c, 0xff,  0x7f, 0x7c, 
  101.    0x80, 0xff,  0xff, 0x00,  0xc0, 0xff,  0xff, 0x01, 
  102.    0xc0, 0xff,  0xff, 0x01,  0xe0, 0xff,  0xff, 0x03, 
  103.    0xe0, 0xff,  0xff, 0x03,  0xe0, 0xff,  0xff, 0x03, 
  104.    0xe0, 0xff,  0xff, 0x01,  0xe0, 0xff,  0xff, 0x49, 
  105.    0x82, 0xff,  0xff, 0x34,  0x14, 0xfe,  0x3f, 0x42, 
  106.    0xe2, 0xff,  0x9f, 0x34,  0x40, 0xfe,  0x3f, 0x41, 
  107.    0xbe, 0xfd,  0xdf, 0x1e,  0x00, 0xf8,  0x1f, 0x01, 
  108.    0xfe, 0xfd,  0xdf, 0x7f,  0x00, 0xfc,  0x1f, 0x00, 
  109.    0x00, 0xfc,  0x1f, 0x00,  0x00, 0xfc,  0x3f, 0x00, 
  110.    0x00, 0xfe,  0x1f, 0x00,  0x00, 0xfe,  0x3f, 0x00, 
  111.    0x00, 0xff,  0x3f, 0x00,  0xc0, 0xff,  0xff, 0x00, 
  112.    0xfc, 0xff,  0xff, 0x3f,  0xfe, 0xff,  0xff, 0x7f, 
  113.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
  114.  
  115. #define bomb4_width 32
  116. #define bomb4_height 32
  117. static char bomb4_bits[] = {
  118.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  119.    0x00, 0x00,  0x00, 0x00,  0x00, 0xc0,  0x07, 0x00, 
  120.    0x00, 0x78,  0x10, 0x00,  0x00, 0x0f,  0x46, 0x00, 
  121.    0x80, 0x61,  0x81, 0x00,  0xc0, 0x1c,  0x00, 0x01, 
  122.    0x40, 0x02,  0x00, 0x00,  0x20, 0x01,  0x00, 0x00, 
  123.    0x20, 0x01,  0x00, 0x00,  0x20, 0x00,  0x00, 0x00, 
  124.    0x20, 0x00,  0x00, 0x00,  0x40, 0x00,  0x00, 0x00, 
  125.    0x80, 0x00,  0x00, 0x00,  0x00, 0x02,  0x00, 0x00, 
  126.    0x00, 0x02,  0x00, 0x00,  0x00, 0x04,  0x00, 0x00, 
  127.    0x00, 0x04,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  128.    0x00, 0x04,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  129.    0x00, 0x04,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  130.    0x00, 0x04,  0x00, 0x00,  0x00, 0x02,  0x00, 0x00, 
  131.    0x00, 0x01,  0x00, 0x00,  0xc0, 0x00,  0x00, 0x00, 
  132.    0x2c, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  133.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
  134.  
  135. /* This is the name of a family of programs, so argv[0] inadequate. */
  136.  
  137. #define PROGRAMNAME "xconq"
  138.  
  139. /* Name of default font - why is this wired in? */
  140.  
  141. #define STANDARD "standard"
  142.  
  143. /* Magic number meaning that this pixmap intentionally left blank. */
  144.  
  145. #define NOPIXMAP 17
  146.  
  147. #define INFOLINES 4
  148.  
  149. #define BH 32
  150.  
  151. /* Use with caution - variable name "side" embedded! */
  152.  
  153. #define sd() ((Screeno *) side->display)
  154.  
  155. #define sdd() (((Screeno *) side->display)->disp)
  156.  
  157. typedef unsigned int unint;
  158.  
  159. /* GC rules are for different fonts etc, but not colors or bitmaps. */
  160.  
  161. typedef struct a_screen {
  162.     Display *disp;
  163.     GC gc;            /* a tmp graphics context for this display */
  164.     GC flashgc;            /* The gc for drawing the flash lines. */
  165.     GC textgc;            /* foreground on background text */
  166.     GC icongc;            /* icon graphics context */
  167.     GC invicongc;        /* icon gc inverted colors. */
  168.     GC varicongc;        /* This is an icon gc with variable fgcolor. */
  169.     GC unitgc;            /* unit bitmap printing gc. */
  170.     GC unittextgc;        /* unit text printing gc. */
  171.     GC cleargc;            /* The gc to use for clearing areas. */
  172.     GC clearbitgc;              /* gc for clearing bitmaps */
  173.     XFontStruct *textfont;    /* font for text display */
  174.     XFontStruct *iconfont;    /* utility font with assorted icons */
  175.     XFontStruct *unitfont;    /* font for unit characters */
  176.     Pixmap bombpics[4];        /* mushroom clouds */
  177.     Pixmap unitpics[MAXUTYPES];    /* used instead of font sometimes */
  178.     Pixmap wbdots, bwdots;    /* blue border and dotted backgrounds */
  179.     Cursor curs;        /* the cursor object itself */
  180. } Screeno;
  181.  
  182. extern int giventime;
  183.  
  184. /* Random function declarations. */
  185.  
  186. XFontStruct * open_font();
  187. Pixmap load_bitmap();
  188. void get_font_size();
  189. Cursor make_cursor();
  190.  
  191. /* The array of screen objects. */
  192.  
  193. Screeno screens[MAXSIDES];      /* All the "screen objects" */
  194.  
  195. /* Values of parameters generally tied to fonts and the like. */
  196.  
  197. int hw = 20;
  198. int hh = 22;
  199. int hch = 17;
  200. int margin = 2;
  201. int bd = 1;
  202.  
  203. int helpwinlines = 1;           /* size of help window */
  204.  
  205. bool rootcursor;                /* true if using parent window's cursor */
  206.  
  207. /* Put in a default player, probably the invoker of the program. */
  208. /* An empty host name will confuse everybody. */
  209.  
  210. add_default_player()
  211. {
  212. #ifdef UNIX
  213.     add_player(TRUE, getenv("DISPLAY"));
  214. #endif /* UNIX */
  215. }
  216.  
  217. /* Ignore ^C if humans in the game, do it otherwise, including when the */
  218. /* last human player turns into a machine (this is called by option cmd). */
  219. /* Attempts to be more clever seem to be bad news. */
  220.  
  221. init_sighandlers()
  222. {
  223. #ifdef UNIX
  224.     if (numhumans > 0 && !Debug) {
  225.     signal(SIGINT, SIG_IGN);
  226.     } else {
  227.     signal(SIGINT, SIG_DFL);
  228.     }
  229. #endif /* UNIX */
  230. }
  231.  
  232. /* Note that the open_display function syncronizes the X server when the */
  233. /* Debug flag is set. */
  234.  
  235. open_display(side)
  236. Side *side;
  237. {
  238.     if (Debug) printf("starting open_display\n");
  239.  
  240.     side->display = (long) &(screens[side_number(side)]);
  241.  
  242.     if (Debug) printf("open_display: XopenDisplay('%s')\n", side->host);
  243.  
  244.     if(NULL == (sdd() = XOpenDisplay(side->host)))
  245.     {
  246.     fprintf(stderr, "Cannot open display ('%s')\n", side->host);
  247.     exit(1);
  248.     }
  249.     if (Debug) {
  250.       XSynchronize(sdd(), TRUE);
  251.       printf("Synching the X server.\n");
  252.     }
  253.     init_cmaps(side);
  254.     side->main = XCreateSimpleWindow(sdd(), DefaultRootWindow(sdd()),
  255.                      50, 3,
  256.                      display_width(side), display_height(side),
  257.                      3, white_color(side), black_color(side));
  258.     XSetWindowColormap(sdd(), side->main, side->cmap);
  259.     read_options(side);
  260.     if (Debug) printf("done open_display\n");
  261.     return (sdd() != NULL);
  262. }
  263.  
  264. /* A predicate that tests whether our display can safely be written to. */
  265.  
  266. active_display(side)
  267. Side *side;
  268. {
  269.     return (side && side->host && !side->lost && side->display);
  270. }
  271.  
  272. display_width(side)
  273. Side *side;
  274. {
  275.     return ((19 * XDisplayWidth(sdd(), DefaultScreen(sdd()))) / 20);
  276. }
  277.  
  278. display_height(side)
  279. Side *side;
  280. {
  281.     return ((19 * XDisplayHeight(sdd(), DefaultScreen(sdd()))) / 20);
  282. }
  283.  
  284. /* Most X displays have enough screen to do a world map. */
  285.  
  286. world_display(side) Side *side; {  return TRUE;  }
  287.  
  288. /* Could use handlers for X failures... */
  289.  
  290. /* Do misc setup thingies. */
  291.  
  292. /* Do the rigmarole to convert all those short arrays into X-approved */
  293. /* Bitmaps.  Note that this has to be for *each* display separately (!) */
  294. /* Also get the cursor shape.  If the hardware can't hack the desired */
  295. /* cursor size, warn about it and just use the root window's cursor. */
  296. /* 0x0 cursor specs seem to be don't cares - machine can handle any size */
  297. /* X11 also needs gazillions of GCs, since we've got so many fonts and */
  298. /* colors and bitmaps. */
  299.  
  300. init_misc(side)
  301. Side *side;
  302. {
  303.     int u, w, h;
  304.     unsigned long mask;
  305.     XGCValues values;
  306.     Pixmap mmask, mcurs, dots;
  307.     GC gc;
  308.  
  309.     side->margin = margin;
  310.     side->bd = bd;
  311.     side->hw = hw;
  312.     side->hh = hh;
  313.     side->hch = hch;
  314.     mask = GCForeground | GCBackground;
  315.     values.foreground = side->fgcolor;
  316.     values.background = side->bgcolor;
  317.     gc = XCreateGC(sdd(), side->main, mask, &values);
  318.     sd()->gc = XCreateGC(sdd(), side->main, mask, &values);
  319.     sd()->flashgc = XCreateGC(sdd(), side->main, mask, &values);
  320.     sd()->textgc = XCreateGC(sdd(), side->main, mask, &values);
  321.     sd()->icongc = XCreateGC(sdd(), side->main, mask, &values);
  322.     sd()->varicongc = XCreateGC(sdd(), side->main, mask, &values);
  323.     sd()->unitgc = XCreateGC(sdd(), side->main, mask, &values);
  324.     sd()->unittextgc = XCreateGC(sdd(), side->main, mask, &values);
  325.     values.foreground = side->bgcolor;
  326.     values.background = side->fgcolor;
  327.     sd()->invicongc = XCreateGC(sdd(), side->main, mask, &values);
  328.     values.function = GXclear;
  329.     mask = GCFunction;
  330.     sd()->cleargc = XCreateGC(sdd(), side->main, mask, &values);
  331.  
  332.     sd()->textfont = open_font(side, TEXTFONT, "TextFont", NULL);
  333.     get_font_size(sd()->textfont, &(side->fw), &(side->fh) );
  334.     sd()->iconfont = open_font(side, ICONFONT, "IconFont", sd()->textfont);
  335.     get_font_size(sd()->iconfont, &(side->hw), &(side->hh) );
  336.     if (period.fontname != NULL && strlen(period.fontname) > 0) {
  337.     sd()->unitfont = 
  338.         open_font(side, period.fontname, "UnitFont", sd()->textfont);
  339.     get_font_size(sd()->unitfont, &(side->uw), &(side->uh) );
  340.     } else {
  341.           sd()->unitfont = 
  342.         open_font(side, STANDARD, "UnitFont", sd()->textfont);
  343.     get_font_size(sd()->unitfont, &(side->uw), &(side->uh) );
  344.     }
  345.     XSetFont(sdd(), sd()->textgc, sd()->textfont->fid);
  346.     XSetFont(sdd(), sd()->icongc, sd()->iconfont->fid);
  347.     mask = GCFillStyle | GCGraphicsExposures;
  348.     values.fill_style = FillSolid;
  349.     values.graphics_exposures = FALSE;
  350.     XChangeGC(sdd(), sd()->unitgc, mask, &values);
  351.     XSetFont(sdd(), sd()->unittextgc, sd()->unitfont->fid);
  352.     XSetFont(sdd(), sd()->invicongc, sd()->iconfont->fid);
  353.     XSetFont(sdd(), sd()->varicongc, sd()->iconfont->fid);
  354.     XSetFunction(sdd(), sd()->flashgc, GXinvert);
  355.  
  356.     mmask = XCreateBitmapFromData(sdd(), side->main,
  357.                     mask_bits, mask_width, mask_height);
  358.     mcurs = XCreateBitmapFromData(sdd(), side->main,
  359.                     curs_bits, curs_width, curs_height);
  360.  
  361.     dots  = XCreateBitmapFromData(sdd(), side->main, 
  362.                   dots_bits, dots_width, dots_height);
  363.  
  364.     sd()->bombpics[0] = XCreateBitmapFromData(sdd(), side->main,
  365.     bomb1_bits, bomb1_width, bomb1_height);
  366.     sd()->bombpics[1] = XCreateBitmapFromData(sdd(), side->main,
  367.         bomb2_bits, bomb2_width, bomb2_height);
  368.     sd()->bombpics[2] = XCreateBitmapFromData(sdd(), side->main,
  369.     bomb3_bits, bomb3_width, bomb3_height);
  370.     sd()->bombpics[3] = XCreateBitmapFromData(sdd(), side->main,
  371.     bomb4_bits, bomb4_width, bomb4_height);
  372.     for_all_unit_types(u) {
  373.     if (utypes[u].bitmapname && (strlen(utypes[u].bitmapname) > 0)) {
  374.         sd()->unitpics[u] = load_bitmap(side, utypes[u].bitmapname);
  375.     } else {
  376.         utypes[u].bitmapname = NULL;
  377.     }
  378.     }
  379.     if (Debug) printf("Bitmaps stored ...\n");
  380.  
  381.     sd()->wbdots = XCreatePixmap(sdd(), side->main, dots_width, dots_height,
  382.                  DefaultDepth(sdd(), DefaultScreen(sdd())));
  383.     sd()->bwdots = XCreatePixmap(sdd(), side->main, dots_width, dots_height,
  384.                  DefaultDepth(sdd(), DefaultScreen(sdd())));
  385.  
  386.     /* Since clearbitgc has to have a depth of 1 we'll */
  387.     /* hang it off bombpics[0] */
  388.     mask = GCFunction;
  389.     values.function = GXclear;
  390.     sd()->clearbitgc = XCreateGC(sdd(), sd()->bombpics[0], mask, &values);
  391.  
  392.     XSetForeground(sdd(), gc, side->fgcolor);
  393.     XSetBackground(sdd(), gc, side->bgcolor);
  394.     XSetStipple(sdd(), gc, dots);
  395.     XSetFillStyle(sdd(), gc, FillOpaqueStippled);
  396.     XFillRectangle(sdd(), sd()->wbdots, gc, 0, 0, dots_width, dots_height);
  397.  
  398.     XSetForeground(sdd(), gc, side->bgcolor);
  399.     XSetBackground(sdd(), gc, side->fgcolor);
  400.     XFillRectangle(sdd(), sd()->bwdots, gc, 0, 0, dots_width, dots_height);
  401.     if (Debug) printf("Tiles stored ...\n");
  402.  
  403.     rootcursor = FALSE;
  404.     XQueryBestCursor(sdd(), side->main, curs_width, curs_height, &w, &h);
  405.     if (Debug) printf("Allowed cursor shape is %dx%d\n", w, h);
  406.     if (w >= curs_width && h >= curs_height) {
  407.         sd()->curs =
  408.       make_cursor(side, mcurs, mmask, white_color(side),
  409.               black_color(side), 7, 7);
  410.        
  411.     } else {
  412.     fprintf(stderr, "Warning: Can't have %dx%d cursors on \"%s\"!\n",
  413.         curs_width, curs_height, side->host);
  414.         fprintf(stderr, "Using default cursor...\n");
  415.         rootcursor = TRUE;
  416.     }
  417.     if (Debug) printf("Cursor stored ...\n");
  418.     XFreeGC(sdd(), gc);
  419.     XFreePixmap(sdd(), dots);
  420.     XFreePixmap(sdd(), mmask);
  421.     XFreePixmap(sdd(), mcurs);
  422. }
  423.  
  424. /* Since XCreatePixmapCursor() takes XColors and not pixel values we */
  425. /* have to look the colors associated with the foreground and */
  426. /* background pixel values up in the color table and pass them to */
  427. /* XCreatePixmapCursor(). */
  428.    
  429. Cursor 
  430. make_cursor(side, curs, mask, foreground, background, x, y)
  431. Side *side;
  432. Pixmap curs, mask;
  433. unsigned long foreground, background;
  434. unsigned int x, y;
  435. {
  436.     XColor defs[2];
  437.  
  438.     defs[0].pixel = foreground;
  439.     defs[1].pixel = background;
  440.     XQueryColors(sdd(), side->cmap, defs, 2);
  441.     return  XCreatePixmapCursor(sdd(), curs, mask, &defs[0], &defs[1], x, y);
  442. }
  443.  
  444. /* Since font lookup is still not smart among Xs, this is a general routine */
  445. /* that can deal with unopenable, missing, etc, fonts, as well as the use of */
  446. /* .Xdefaults.  One of the inputs is another font that can be substituted if */
  447. /* necessary. */
  448.  
  449. XFontStruct *
  450. open_font(side, name, xdefault, altfont)
  451. Side *side;
  452. char *name, *xdefault;
  453. XFontStruct * altfont;
  454. {
  455.     char *firstname, *altname;
  456.     XFontStruct * font;
  457.  
  458.     if ((altname = XGetDefault(sdd(), PROGRAMNAME, xdefault)) != NULL)
  459.     name = altname;
  460.     firstname = name;
  461.     if ((font = XLoadQueryFont(sdd(), name)) == NULL) {
  462.     add_font_path(side,XFONTPATH);
  463.     if ((font = XLoadQueryFont(sdd(), name)) == NULL) {
  464.         fprintf(stderr, "Can't open font \"%s\" on \"%s\"\n",
  465.             name, side->host);
  466.         if (altfont != NULL) {
  467.         fprintf(stderr, "Substituting another font...\n");
  468.         return altfont;
  469.         } else {
  470.         fprintf(stderr, "No font to substitute!!\n");
  471.         exit(1);
  472.         }
  473.     }
  474.     }
  475.     if (Debug) printf("Opened font \"%s\" ...\n", name);
  476.     return font;
  477. }
  478.  
  479. /* Force X11 font fanciness into semblance of X10 font plainness. */
  480.  
  481. void
  482. get_font_size(font, width, height)
  483. XFontStruct * font;
  484. short *width, *height;
  485. {
  486. #ifdef SCO_UNIX
  487.     /* this seems to work best; for some reason, the bounds width
  488.      * doesn't seem to give the right result.
  489.      */
  490.     *width = XTextWidth(font, "12345678", 8) / 8;
  491.     *height = font->max_bounds.ascent + font->max_bounds.descent;
  492. #else
  493.     *width = font->max_bounds.rbearing - font->min_bounds.lbearing;
  494.     *height = font->max_bounds.ascent + font->max_bounds.descent;
  495. #endif /* SCO_UNIX */
  496.     if (Debug) {
  497.     printf("rbearing = %d lbearing = %d\n",
  498.            (int)font->max_bounds.rbearing, (int)font->min_bounds.lbearing);
  499.     printf("returning font size %d %d\n", (int)*width, (int)*height);
  500.     }
  501. }
  502.  
  503. /* Try to load a bitmap of the given name - can be either X11-only (.b11) */
  504. /* or X10 (.b) bitmaps, but prefer X11 flavor. */
  505.  
  506. Pixmap
  507. load_bitmap(side, name)
  508. Side *side;
  509. char *name;
  510. {
  511.     int w, h, junk, a;
  512.     Pixmap rslt;
  513.  
  514.     make_pathname(NULL, name, "b11", spbuf);
  515.     a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &junk, &junk);
  516.     if (a == BitmapSuccess) return rslt;
  517.     make_pathname(XCONQLIB, name, "b11", spbuf);
  518.     a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &junk, &junk);
  519.     if (a == BitmapSuccess) return rslt;
  520.     make_pathname(XCONQLIB, name, "b", spbuf);
  521.     a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &junk, &junk);
  522.     if (a == BitmapSuccess) return rslt;
  523.     fprintf(stderr, "Bitmap name \"%s\" not found anywhere!\n", name);
  524.     return (-1);
  525. }
  526.  
  527. /* This routine has to be able to cope with window managers constraining */
  528. /* size.  Actually, the main window was already opened when the display */
  529. /* was opened, so the name is not quite accurate! */
  530.  
  531. create_main_window(side)
  532. Side *side;
  533. {
  534.     Pixmap dots;
  535.     XSizeHints hints;
  536.           
  537.     XStoreName(sdd(), side->main, PROGRAMNAME);
  538.     dots = (side->bonw ? sd()->bwdots : sd()->wbdots); 
  539.     XSetWindowBackgroundPixmap(sdd(), side->main, dots);
  540.  
  541.     hints.width = side->mw;
  542.     hints.height = side->mh;
  543.     hints.min_width = side->mw;
  544.     hints.min_height = side->mh;
  545.     hints.flags = PSize|PMinSize;
  546.     XSetNormalHints(sdd(), side->main, &hints);
  547. }
  548.  
  549. /* Help window is not necessarily a subwindow, though it might be sometimes. */
  550.  
  551. create_help_window(side)
  552. Side *side;
  553. {
  554.     helpwinlines =
  555.     max(45, (24 + period.numrtypes + period.numttypes + period.numutypes));
  556.  
  557.     side->help = XCreateSimpleWindow(sdd(), DefaultRootWindow(sdd()),
  558.                      0, 0, 80*side->fw+1,
  559.                      helpwinlines*side->fh+1,
  560.                      1, side->fgcolor, side->bgcolor);
  561.     XStoreName(sdd(), side->help, "xconq-help");
  562.     XSetWindowColormap(sdd(), side->help, side->cmap);
  563. }
  564.  
  565. /* Subwindow creator.  If name is not null, create a split window. */
  566.  
  567. create_window(side, x, y, w, h, name)
  568. Side *side;
  569. int x, y, w, h;
  570. char *name;
  571. {
  572.     int win;
  573.     win =  XCreateSimpleWindow(sdd(),
  574.     name ? DefaultRootWindow(sdd()) :  side->main,
  575.     x, y, w, h, 1, side->fgcolor, side->bgcolor);
  576.     if (name)
  577.     XStoreName(sdd(), win, name);
  578.     XSetWindowColormap(sdd(), win, side->cmap);
  579.     return win;
  580. }
  581.  
  582. /* Do little things necesary to make it all go, in this case mapping all */
  583. /* the windows (except help win). */
  584.  
  585. fixup_windows(side)
  586. Side *side;
  587. {
  588.     XMapWindow(sdd(), side->main);
  589.     XMapSubwindows(sdd(), side->main);
  590.     if (side->split) {
  591.     XMapWindow(sdd(), side->state);
  592.     XMapWindow(sdd(), side->map);
  593.     XMapWindow(sdd(), side->world);
  594.     }
  595.     if (!giventime) XUnmapWindow(sdd(), side->clock);
  596.     if (!rootcursor) XDefineCursor(sdd(), side->map, sd()->curs);
  597. }
  598.  
  599. /* Specify the sorts of input that will be allowed - main window needs to */
  600. /* see mouse buttons so unit type selection works right. */
  601.  
  602. enable_input(side)
  603. Side *side;
  604. {
  605.     if (side->split) {
  606.     XSelectInput(sdd(), side->main,
  607.         KeyPressMask|ExposureMask|StructureNotifyMask);
  608.     XSelectInput(sdd(), side->map,
  609.         KeyPressMask|ButtonPressMask|ExposureMask|StructureNotifyMask);
  610.     XSelectInput(sdd(), side->state,
  611.         KeyPressMask|ButtonPressMask|ExposureMask);
  612.     }
  613.     else {
  614.     XSelectInput(sdd(), side->main, KeyPressMask|ExposureMask);
  615.     XSelectInput(sdd(), side->map, ButtonPressMask|ExposureMask);
  616.     XSelectInput(sdd(), side->state, ButtonPressMask|ExposureMask);
  617.     }
  618.     XSelectInput(sdd(), side->help, KeyPressMask|ExposureMask);
  619.  
  620.     XSelectInput(sdd(), side->msg, ExposureMask);
  621.     XSelectInput(sdd(), side->info, ExposureMask); 
  622.     XSelectInput(sdd(), side->prompt, ExposureMask); 
  623.     XSelectInput(sdd(), side->timemode, ExposureMask);
  624.     XSelectInput(sdd(), side->clock, ExposureMask);
  625.     XSelectInput(sdd(), side->sides, ExposureMask);
  626.     XSelectInput(sdd(), side->world, ExposureMask);
  627. }
  628.  
  629. /* Move windows and change their sizes to correspond with the new sizes of */
  630. /* viewports, etc */
  631.  
  632. reset_misc(side)
  633. Side *side;
  634. {
  635.     Pixmap dots;
  636.     XSizeHints hints;
  637.     XGCValues values;
  638.     unsigned int gcmask;
  639.  
  640.     dots = (side->bonw ? sd()->bwdots : sd()->wbdots); 
  641.  
  642.     XResizeWindow(sdd(), side->main, side->mw, side->mh);
  643.     hints.width = side->mw;  hints.height = side->mh;
  644.     hints.min_width = side->mw;  hints.min_height = side->mh;
  645.     hints.flags = PSize|PMinSize;
  646.     XSetNormalHints(sdd(), side->main, &hints);
  647.  
  648.     XSetWindowBackgroundPixmap(sdd(), side->main, dots);
  649.     XSetWindowBackground(sdd(), side->msg, side->bgcolor);
  650.     XSetWindowBackground(sdd(), side->info, side->bgcolor); 
  651.     XSetWindowBackground(sdd(), side->prompt, side->bgcolor); 
  652.     XSetWindowBackground(sdd(), side->map, side->bgcolor);
  653.     XSetWindowBackground(sdd(), side->timemode, side->bgcolor);
  654.     XSetWindowBackground(sdd(), side->clock, side->bgcolor);
  655.     XSetWindowBackground(sdd(), side->state, side->bgcolor);
  656.     XSetWindowBackground(sdd(), side->help, side->bgcolor);
  657.     XSetWindowBackground(sdd(), side->sides, side->bgcolor);
  658.     XSetWindowBackground(sdd(), side->world, side->bgcolor);
  659.     XSetWindowBorder(sdd(), side->msg, side->fgcolor);
  660.     XSetWindowBorder(sdd(), side->info, side->fgcolor); 
  661.     XSetWindowBorder(sdd(), side->prompt, side->fgcolor); 
  662.     XSetWindowBorder(sdd(), side->map, side->fgcolor);
  663.     XSetWindowBorder(sdd(), side->timemode, side->fgcolor);
  664.     XSetWindowBorder(sdd(), side->clock, side->fgcolor);
  665.     XSetWindowBorder(sdd(), side->state, side->fgcolor);
  666.     XSetWindowBorder(sdd(), side->help, side->fgcolor);
  667.     XSetWindowBorder(sdd(), side->sides, side->fgcolor);
  668.     XSetWindowBorder(sdd(), side->world, side->fgcolor);
  669.  
  670.     gcmask = GCForeground | GCBackground;
  671.     values.foreground = side->fgcolor;
  672.     values.background = side->bgcolor;
  673.     XChangeGC(sdd(), sd()->gc, gcmask, &values);
  674.     XChangeGC(sdd(), sd()->flashgc, gcmask, &values);
  675.     XChangeGC(sdd(), sd()->textgc, gcmask, &values);
  676.     XChangeGC(sdd(), sd()->icongc, gcmask, &values);
  677.     XChangeGC(sdd(), sd()->unitgc, gcmask, &values);
  678.     values.foreground = side->bgcolor;
  679.     values.background = side->fgcolor;
  680.     XChangeGC(sdd(), sd()->invicongc, gcmask, &values);
  681. }
  682.  
  683. /* Alter the size and position of a window. */
  684.  
  685. change_window(side, win, x, y, w, h)
  686. Side *side;
  687. Window win;
  688. int x, y, w, h;
  689. {
  690.     unsigned int mask;
  691.     XWindowChanges changes;
  692.  
  693.     if (active_display(side)) {
  694.     if (x >= 0) {
  695.         if (w >= 0) {
  696.         mask = CWX | CWY | CWWidth | CWHeight;
  697.         changes.x = x;  changes.y = y;
  698.         changes.width = w;  changes.height = h;
  699.         } else {
  700.         mask = CWX | CWY;
  701.         changes.x = x;  changes.y = y;
  702.         }
  703.     } else {
  704.         mask = CWWidth | CWHeight;
  705.         changes.width = w;  changes.height = h;
  706.     }
  707.     }
  708.     XConfigureWindow(sdd(), win, mask, &changes);
  709. }
  710.  
  711. /* Return the number of colors - this is used to guess about monochromeness. */
  712.  
  713. display_colors(side)
  714. Side *side;
  715. {
  716.     return XDisplayCells(sdd(), DefaultScreen(sdd()));
  717. }
  718.  
  719. white_color(side)
  720. Side *side;
  721. {
  722. /*    return request_color(side,"white");*/
  723.     return WhitePixel(sdd(), DefaultScreen(sdd()));
  724. }
  725.  
  726. black_color(side)
  727. Side *side;
  728. {
  729. /*    return request_color(side,"black");*/
  730.     return BlackPixel(sdd(), DefaultScreen(sdd()));
  731. }
  732.  
  733. /* Get a color set up and warn if not getting what was asked for. */
  734.  
  735. long
  736. request_color(side, name)
  737. Side *side;
  738. char *name;
  739. {
  740.     XColor c, avail;
  741.  
  742.     if (Debug) printf("Allocating %s\n", name);
  743.     XAllocNamedColor(sdd(), side->cmap, name, &avail, &c);
  744.     if ( abs(c.red - avail.red) >= COLOR_DIFF ||
  745.          abs(c.green - avail.green) >= COLOR_DIFF || 
  746.      abs(c.blue - avail.blue) >= COLOR_DIFF ) {
  747.     fprintf(stderr, "Warning: %s color (%d) not exact on \"%s\"!\n",
  748.         name, c.pixel, side->host);
  749.     fprintf(stderr, "Is %d %d %d instead of %d %d %d\n",
  750.         avail.red, avail.green, avail.blue, c.red, c.green, c.blue);
  751.     }
  752.     return avail.pixel;
  753. }
  754.  
  755. /* Main funnel for input returns both mouse and keyboard events, and maybe */
  756. /* other kinds eventually.  Some events like window exposure are handled */
  757. /* strictly locally. */
  758.  
  759. get_input()
  760. {
  761. #ifdef SELECT2
  762.     int i, mask;
  763.     Side *side, *asides[32];
  764.  
  765.     mask = 0;
  766.     for_all_sides(side) {
  767.     if (active_display(side)) {
  768.         mask |= (1 << ConnectionNumber(sdd()));
  769.         asides[ConnectionNumber(sdd())] = side;
  770.         while (XPending(sdd()) > 0) {
  771.         process_events(side);
  772.         }
  773.         side->lasttime = time(0);
  774.     }
  775.     }
  776.     if (Debug) {
  777.     printf("Waiting for input from ");
  778.     for_all_sides(side)
  779.         if (active_display(side)) printf("%s ", side->host);
  780.     printf("\n");
  781.     }
  782.     if (select(32, &mask, 0, 0, 0) < 0) {
  783.     fprintf(stderr, "error in select!\n");
  784.     abort();
  785.     } else {
  786.     for (i = 0; i < 32; ++i) {
  787.         if (mask & (1 << i)) {
  788.         process_events(asides[i]);
  789.         asides[i]->timeleft -= (time(0) - asides[i]->lasttime); 
  790.         update_clock(asides[i]);
  791.         }
  792.     }
  793.     }
  794. #else
  795.     extern Side *curside;
  796.  
  797.     /* No simultaneity, but there's no portable way to do it, sigh */
  798.     if (active_display(curside) && humanside(curside)) {
  799.     if (Debug) printf("Waiting for input from %s\n", curside->host);
  800.     process_events(curside);
  801.     }
  802. #endif /* SELECT2 */
  803. }
  804.  
  805. /* Look at a single event and fill the request structure appropriately. */
  806.  
  807. process_events(side)
  808. Side *side;
  809. {
  810.     XEvent evt;
  811.     char buf[BUFSIZE];
  812.     int nchar, rawx, rawy;
  813.     int win;
  814.     unsigned int junk;
  815.  
  816.     side->reqtype = GARBAGE;
  817.     XNextEvent(sdd(), &evt);
  818.     switch (evt.type) {
  819.     case KeyPress:
  820.     nchar = XLookupString(&evt, buf, BUFSIZE, NULL, NULL);
  821.     if (nchar > 0) {
  822.         side->reqtype = KEYBOARD;
  823.         side->reqch = *buf;
  824.         if (Debug) printf("Host %s returns key '%c'\n",
  825.                   side->host, side->reqch);
  826.     }
  827.     break;
  828.     case ButtonPress:
  829.     win = evt.xbutton.window;
  830.     if (win == side->map) {
  831.         rawx = evt.xbutton.x;  rawy = evt.xbutton.y; 
  832.         side->reqtype = MAPPOS;
  833.         deform(side, rawx, rawy, &(side->reqx), &(side->reqy));
  834.         if (Debug) printf("Host %s returns map %d %d\n",
  835.                   side->host, side->reqx, side->reqy);
  836.     } else if (win == side->state) {
  837.         rawx = evt.xbutton.x;  rawy = evt.xbutton.y; 
  838.         side->reqtype = UNITTYPE;
  839.         side->requtype = rawy / max(side->hh, side->fh);
  840.         if (Debug) printf("Host %s returns unit type %d\n",
  841.                   side->host, side->requtype);
  842.     }
  843.     break;
  844.     case Expose:
  845.     win = evt.xexpose.window;
  846.  
  847.     /* if this is the first expose, install our colormap
  848.      * (if we need to)
  849.      */
  850.     if (side->InstallCmap) {
  851.         side->InstallCmap = 0;
  852.         XInstallColormap(sdd(), side->cmap);
  853.     }
  854.  
  855.         /* get rid of all other Expose events on queue */
  856.         while (XCheckTypedWindowEvent(sdd(), win, Expose, &evt));
  857.  
  858.         /* don't need to check which window got event,
  859.          * because we take care of that with the
  860.          * event masks.
  861.          */
  862.  
  863.         clear_window(side, win);
  864.         if (win == side->map)
  865.         show_map(side);
  866.         else if (win == side->state)
  867.         show_state(side);
  868.         else if (win == side->world)
  869.         show_world(side);
  870.         else if (win == side->msg)
  871.         show_note(side);
  872.         else if (win == side->info)
  873.         show_info(side);
  874.         else if (win == side->prompt)
  875.         show_prompt(side);
  876.         else if (win == side->sides)
  877.         show_all_sides(side);
  878.         else if (win == side->timemode)
  879.         show_timemode(side);
  880.         else if (win == side->clock)
  881.         show_clock(side);
  882.         else if (win == side->help) {
  883.         side->reqch = '\014';
  884.         x_help(side);    /* redraw help window */
  885.         }
  886.         flush_output(side);
  887.  
  888.         if (Debug) printf("Host %s exposes itself\n", side->host);
  889.         return FALSE;
  890.         break;
  891.     case ConfigureNotify:
  892.     win = evt.xexpose.window;
  893.  
  894.         /* window has been resized */
  895.         if (win == side->map) {
  896.         undraw_box(side);
  897.  
  898.         side->vw = evt.xconfigure.width / side->hw;
  899.         side->vh = evt.xconfigure.height / side->hch;
  900.             side->vw2 = side->vw / 2;
  901.             side->vh2 = side->vh / 2;
  902. /*            flush_input(side);*/
  903.         set_sizes(side);    /* adjust viewport */
  904.         /* count on exposure event to draw map */
  905.         draw_box(side);
  906.         }
  907.         else if (win == side->main) {
  908.             int sy, sdy;
  909.         int  remain;
  910.  
  911.             remain = side->fh * (INFOLINES + 1) + 3 * side->bd;
  912.         side->nh = (evt.xconfigure.height - remain) / side->fh;
  913.         side->nh = min(side->nh, MAXNOTES);
  914.         side->nh = max(1, side->nh);
  915.         set_sizes(side);
  916.  
  917.         sy = 0;  sdy = side->nh * side->fh;
  918.         change_window(side, side->msg, 0, sy, side->lw, sdy);
  919.         sy += sdy + side->bd;  sdy = INFOLINES * side->fh;
  920.         change_window(side, side->info, 0, sy, side->lw, sdy);
  921.         sy += sdy + side->bd;  sdy = 1 * side->fh;
  922.         change_window(side, side->prompt, 0, sy, side->lw, sdy);
  923.         change_window(side, side->timemode,
  924.               side->lw + side->fw, side->th - 4 * side->fh, -1, -1);
  925.         change_window(side, side->sides, side->lw+1, 0, -1, -1);
  926.         /* count on expose to draw all windows */
  927.         }
  928.         break;
  929.  
  930.     case DestroyNotify:
  931.     case CirculateNotify:
  932.     case GravityNotify:
  933.     case MapNotify:
  934.     case ReparentNotify:
  935.     case UnmapNotify:
  936.         break;
  937.     default:
  938. #if 0
  939.         case_panic("event type", evt.type);
  940. #endif
  941.     break;
  942.     }
  943. }
  944.  
  945. /* Freese everything until given side supplies input, use sparingly. */
  946.  
  947. freeze_wait(side)
  948. Side *side;
  949. {
  950.     XEvent evt;
  951.     char buf[BUFSIZE];
  952.     int nchar;
  953.  
  954.     if (Debug) printf("Waiting for a %s event\n", side->host);
  955.     flush_input(side);
  956.     while(TRUE) {
  957.     XNextEvent(sdd(), &evt);
  958.     if (evt.type == KeyPress) {
  959.         nchar = XLookupString(&evt, buf, BUFSIZE, NULL, NULL);
  960.         if (nchar > 0) 
  961.         return *buf;
  962.         else
  963.         return '\0';
  964.     }
  965.     }  
  966. }
  967.  
  968. /* Get rid of extra key/mouse clicks. */
  969.  
  970. flush_input(side)
  971. Side *side;
  972. {
  973.     XEvent evt;
  974.  
  975. /*    if (humanside(side)) XSync(sdd(), TRUE);*/
  976.     if (humanside(side)) {
  977.         while (XCheckTypedWindowEvent(sdd(), side->main, KeyPress, &evt));
  978.         while (XCheckTypedWindowEvent(sdd(), side->help, KeyPress, &evt));
  979.         while (XCheckTypedWindowEvent(sdd(), side->map, ButtonPress, &evt));
  980.         while (XCheckTypedWindowEvent(sdd(), side->state, ButtonPress, &evt));
  981.     XSync(sdd(), FALSE);
  982.     }
  983. }
  984.  
  985. /* Trivial abstraction - sometimes other routines like to ensure all output */
  986. /* actually on the screen. */
  987.  
  988. flush_output(side) 
  989. Side *side; 
  990. {  
  991.     if (humanside(side)) XFlush(sdd());  
  992. }
  993.  
  994. /* General window clearing. */
  995.  
  996. clear_window(side, win)
  997. Side *side;
  998. Window win;
  999. {
  1000.     XClearWindow(sdd(), win);
  1001. }
  1002.  
  1003. /* Draw a single horizontal constant-color bar on the world map.  If part */
  1004. /* would not be drawn because of the map's obliqueness, cut it in two and */
  1005. /* wrap one of the pieces around. */
  1006.  
  1007. draw_bar(side, x, y, len, color)
  1008. Side *side;
  1009. int x, y, len, color;
  1010. {
  1011.     int sx1, sx2, sy, sww;
  1012.  
  1013.     w_xform(side, x, y, &sx1, &sy);
  1014.     w_xform(side, x + len, y, &sx2, &sy);
  1015.     sww = side->mm * world.width;
  1016.     XSetFillStyle(sdd(), sd()->gc, FillSolid);
  1017.     XSetForeground(sdd(), sd()->gc, color);
  1018.     if (sx1 < sww && sx2 >= sww) {
  1019.     XFillRectangle(sdd(), side->world, sd()->gc,
  1020.                sx1, sy, (unint) sww - sx1, (unint) side->mm);
  1021.     XFillRectangle(sdd(), side->world, sd()->gc,
  1022.                0, sy, (unint) sx2 - sww, (unint) side->mm);
  1023.     } else {
  1024.     sx1 %= sww;
  1025.     sx2 %= sww;
  1026.     XFillRectangle(sdd(), side->world, sd()->gc,
  1027.                sx1, sy, (unint) sx2 - sx1, (unint) side->mm);
  1028.     }
  1029. #ifdef STUPIDFLUSH
  1030.     XFlush(sdd());
  1031. #endif /* STUPIDFLUSH */
  1032. }
  1033.  
  1034. /* Invert the outline box on the world map.  This is a little tricky, */
  1035. /* because we want the lines to run through the middle of the world's */
  1036. /* hexes, and because the line drawn should not overlap (or the overlaps */
  1037. /* will be doubly inverted and look strange). */
  1038.  
  1039. invert_box(side, vcx, vcy)
  1040. Side *side;
  1041. int vcx, vcy;
  1042. {
  1043.     int x1, y1, x2, y2, sx1, sy1, sx2, sy2, mm2 = side->mm/2;
  1044.  
  1045.     x1 = vcx - side->vw2 + side->vh2/2;  y1 = vcy - side->vh2;
  1046.     x2 = vcx + side->vw2 - side->vh2/2;  y2 = vcy + side->vh2;
  1047.     w_xform(side, x1, y1, &sx1, &sy1);
  1048.     w_xform(side, x2, y2, &sx2, &sy2);
  1049.     sx1 += mm2;  sy1 -= mm2;  sx2 += mm2;  sy2 += mm2;
  1050.     XSetFunction(sdd(), sd()->gc, GXinvert);
  1051.     /* is this next call really necessary? */
  1052.     XSetLineAttributes(sdd(), sd()->gc, 1, LineSolid, CapButt, JoinMiter);
  1053.     XDrawLine(sdd(), side->world, sd()->gc, sx1, sy1, sx2, sy1);
  1054.     XDrawLine(sdd(), side->world, sd()->gc, sx2, sy1-1, sx2, sy2+1);
  1055.     XDrawLine(sdd(), side->world, sd()->gc, sx2, sy2, sx1, sy2);
  1056.     XDrawLine(sdd(), side->world, sd()->gc, sx1, sy2+1, sx1, sy1-1);
  1057.     XSetFunction(sdd(), sd()->gc, GXcopy);
  1058. }
  1059.  
  1060. /* This interfaces higher-level drawing decisions to the rendition of */
  1061. /* individual pieces of display. */
  1062.  
  1063. draw_terrain_row(side, sx, sy, buf, len, color)
  1064. Side *side;
  1065. int sx, sy, len, color;
  1066. char *buf;
  1067. {
  1068.     sy += sd()->iconfont->max_bounds.ascent;
  1069.     XSetForeground(sdd(), sd()->icongc, color);
  1070.     XDrawString(sdd(), side->map, sd()->icongc, sx, sy, buf, len);
  1071. #ifdef STUPIDFLUSH
  1072.     XFlush(sdd());
  1073. #endif /* STUPIDFLUSH */
  1074. }
  1075.  
  1076. /* Flash a pair of lines up, slow enough to draw the eye, but not so slow */
  1077. /* as to get in the way. */
  1078.  
  1079. flash_position(side, sx, sy, tm)
  1080. Side *side;
  1081. int sx, sy, tm;
  1082. {
  1083.     int sx1, sy1, sx2, sy2;
  1084.  
  1085.     if (tm > 0) {
  1086.     sx1 = sx - 50 + side->hw/2;  sy1 = sy + 50 + side->hch/2;
  1087.     sx2 = sx + 50 + side->hw/2;  sy2 = sy - 50 + side->hch/2;
  1088.     XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy1, sx2, sy2);
  1089.     XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy2, sx2, sy1);
  1090.     flush_output(side);
  1091.     nap(tm);
  1092.     XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy1, sx2, sy2);
  1093.     XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy2, sx2, sy1);
  1094.     }
  1095. }
  1096.  
  1097. /* The "cursor icon" is just a pair of special chars - nothing to do with */
  1098. /* X's notion of cursors. */
  1099.  
  1100. draw_cursor_icon(side, sx, sy)
  1101. Side *side;
  1102. int sx, sy;
  1103. {
  1104.     sy += sd()->iconfont->max_bounds.ascent;
  1105.     XDrawString(sdd(), side->map, sd()->invicongc, sx, sy, "[", 1);
  1106.     XSetForeground(sdd(), sd()->icongc, side->fgcolor);
  1107.     XDrawString(sdd(), side->map, sd()->icongc, sx, sy, "]", 1);
  1108. }
  1109.  
  1110. /* Draw the icon for a hex (given as a char). */
  1111.  
  1112. draw_hex_icon(side, win, sx, sy, color, ch)
  1113. Side *side;
  1114. Window win;
  1115. int sx, sy, color;
  1116. char ch;
  1117. {
  1118.     XSetForeground(sdd(), sd()->varicongc, color);
  1119.     sy += sd()->iconfont->max_bounds.ascent;
  1120.     XDrawString(sdd(), win, sd()->varicongc, sx, sy, &ch, 1);
  1121. }
  1122.  
  1123. /* Draw the number of an unfriendly side (never called for own units). */
  1124.  
  1125. draw_side_number(side, win, sx, sy, n, color)
  1126. Side *side;
  1127. Window win;
  1128. int sx, sy, n, color;
  1129. {
  1130.     char ch = n + '0';
  1131.  
  1132.     if (n >= 0) {
  1133.     XSetForeground(sdd(), sd()->varicongc, color);
  1134.     sy += sd()->iconfont->max_bounds.ascent;
  1135.     XDrawString(sdd(), win, sd()->varicongc, sx, sy, &ch, 1);
  1136.     }
  1137. }
  1138.  
  1139. draw_blast_icon(side, win, sx, sy, type, color)
  1140. Side *side;
  1141. Window win;
  1142. int sx, sy, color;
  1143. char type;
  1144. {
  1145.     char buf[1];
  1146.  
  1147.     XSetForeground(sdd(), sd()->varicongc, color);
  1148.     buf[0] = type;
  1149.     sy += sd()->iconfont->max_bounds.ascent;
  1150.     XDrawString(sdd(), win, sd()->varicongc, sx, sy, buf, 1);
  1151. }
  1152.  
  1153. /* Flash the player's screen in an unmistakable way. */
  1154.  
  1155. invert_whole_map(side)
  1156. Side *side;
  1157. {
  1158.     int sw = side->vw * side->hw, sh = side->vh * side->hh;
  1159.  
  1160.     /* GC needs to be set for inverted drawing */
  1161.     XSetFunction(sdd(), sd()->gc, GXinvert);
  1162.     XFillRectangle(sdd(), side->map, sd()->gc, 0, 0, sw, sh);
  1163.     XSetFunction(sdd(), sd()->gc, GXcopy);
  1164.     flush_output(side);
  1165. }
  1166.  
  1167. /* Draw just one of the mushroom cloud shapes. */
  1168.  
  1169. draw_mushroom(side, x, y, i)
  1170. Side *side;
  1171. int x, y, i;
  1172. {
  1173.     int sx, sy;
  1174.     int color;
  1175.  
  1176.     color = ((side->monochrome || i == 3) ? side->fgcolor : side->bgcolor);
  1177.     xform(side, unwrap(side, x), y, &sx, &sy);
  1178.     XSetForeground(sdd(), sd()->unitgc, color);
  1179.     XSetClipMask(sdd(), sd()->unitgc, sd()->bombpics[i]);
  1180.     XSetClipOrigin(sdd(), sd()->unitgc, sx-BH/4, sy-BH/2);
  1181.     XFillRectangle(sdd(), side->map, sd()->unitgc, sx-BH/4, sy-BH/2, BH, BH);
  1182.     flush_output(side);
  1183. }
  1184.  
  1185. /* Confirm that we can indeed do bar graph displays. */
  1186.  
  1187. bar_graphs(side) Side *side;  {  return TRUE;  }
  1188.  
  1189. /* Do yet another X-toolkit-type function.  This draws a bar graph. */
  1190.  
  1191. draw_graph(side, number, amount, total, critical, title)
  1192. Side *side;
  1193. int number, amount, total, critical;
  1194. {
  1195.     int boxwidth, boxheight, boxoffset, boxleft, barwidth, barheight;
  1196.  
  1197.     if (total > 0) {
  1198.     boxwidth = 5*side->fw;
  1199.     boxheight = (INFOLINES-1)*side->fh - 2*side->margin;
  1200.     boxoffset = side->margin;
  1201.     boxleft = 30*side->fw + number * boxwidth;
  1202.     barwidth = boxwidth / 3;
  1203.     barheight = (boxheight * amount) / total;
  1204.     XSetForeground(sdd(), sd()->gc, side->fgcolor);
  1205.     XFillRectangle(sdd(), side->info, sd()->gc,
  1206.                boxleft + boxwidth/3 - 1, boxoffset - 1,
  1207.                barwidth + 2, boxheight + 2);
  1208.     XSetForeground(sdd(), sd()->gc, side->bgcolor);
  1209.     XFillRectangle(sdd(), side->info, sd()->gc,
  1210.                boxleft + boxwidth/3, boxoffset,
  1211.                barwidth, boxheight);
  1212.     if ( amount > critical)
  1213.       XSetForeground(sdd(), sd()->gc, side->goodcolor);
  1214.     else
  1215.       XSetForeground(sdd(), sd()->gc, side->badcolor);
  1216.     XFillRectangle(sdd(), side->info, sd()->gc,
  1217.                boxleft + boxwidth/3, boxoffset + boxheight - barheight,
  1218.                barwidth, barheight);
  1219.     draw_text(side, side->info,
  1220.           boxleft+(boxwidth-strlen(title)*side->fw)/2,
  1221.           (INFOLINES-1)*side->fh, title, side->fgcolor);
  1222.     }
  1223. }
  1224.  
  1225. /* Splash a unit image (either bitmap or font char) onto some window. */
  1226.  
  1227. draw_unit_icon(side, win, x, y, u, color)
  1228. Side *side;
  1229. Window win;
  1230. int x, y, u, color;
  1231. {
  1232.     char buf[1];
  1233.  
  1234.     y += 3;            /* fudge factor to make x11 look */
  1235.     x += 2;            /*  like X10 (ugh). */
  1236.     if (utypes[u].bitmapname != NULL ) {
  1237.       XSetForeground(sdd(), sd()->unitgc, color);
  1238.       XSetClipMask(sdd(), sd()->unitgc, sd()->unitpics[u]);
  1239.       XSetClipOrigin(sdd(), sd()->unitgc, x, y);
  1240.       XFillRectangle(sdd(), win, sd()->unitgc, x, y, side->uw, side->uh);
  1241.     } else {
  1242.         XSetForeground(sdd(), sd()->unittextgc, color);
  1243.     buf[0] = utypes[u].uchar;
  1244.     y += sd()->unitfont->max_bounds.ascent;
  1245.     XDrawString(sdd(), win, sd()->unittextgc, x, y, buf, 1);
  1246.     }
  1247. }
  1248.  
  1249. /* General text drawer. */
  1250.  
  1251. draw_text(side, win, x, y, str, color)
  1252. Side *side;
  1253. Window win;
  1254. int x, y, color;
  1255. char *str;
  1256. {
  1257.     y += sd()->textfont->max_bounds.ascent;
  1258.     if (color != side->bgcolor) {
  1259.     XSetForeground(sdd(), sd()->textgc, color);
  1260.     XDrawImageString(sdd(), win, sd()->textgc, x, y, str, strlen(str));
  1261.     } else {
  1262.     XSetForeground(sdd(), sd()->textgc, side->bgcolor);
  1263.     XSetBackground(sdd(), sd()->textgc, side->fgcolor);
  1264.     XDrawImageString(sdd(), win, sd()->textgc, x, y, str, strlen(str));
  1265.     XSetBackground(sdd(), sd()->textgc, side->bgcolor);
  1266.     }
  1267. #ifdef STUPIDFLUSH
  1268.     XFlush(sdd());
  1269. #endif /* STUPIDFLUSH */
  1270. }
  1271.  
  1272. /* Draw a line through some side's title. */
  1273.  
  1274. draw_scratchout(side, pos)
  1275. Side *side;
  1276. int pos;
  1277. {
  1278.     XSetForeground(sdd(), sd()->textgc, side->fgcolor);
  1279.     XDrawLine(sdd(), side->sides, sd()->textgc, 0, pos, 30*side->fw, pos);
  1280. }
  1281.  
  1282. /* Beep the beeper! */
  1283.  
  1284. beep(side)
  1285. Side *side;
  1286. {
  1287.     XBell(sdd(), DefaultScreen(sdd()));
  1288. }
  1289.  
  1290. /* Little routines to pop up the help window and make it go away again */
  1291. /* They only get called when display is in use. */
  1292.  
  1293. reveal_help(side)
  1294. Side *side;
  1295. {
  1296.     XEvent evt;
  1297.  
  1298.     XMapWindow(sdd(), side->help);
  1299.     /* wait until this window is exposed to return. */
  1300.     XWindowEvent(sdd(), side->help, ExposureMask, &evt);
  1301.     return TRUE;
  1302. }
  1303.  
  1304. conceal_help(side)
  1305. Side *side;
  1306. {
  1307.     XUnmapWindow(sdd(), side->help);
  1308.     flush_output(side);
  1309. }
  1310.  
  1311. /* Shut a single display down, but only if there's one to operate on. */
  1312. /* Hit the display slot, for safety. */
  1313.  
  1314. close_display(side)
  1315. Side *side;
  1316. {
  1317.     XCloseDisplay(sdd());
  1318.     side->display = (long) NULL;
  1319. }
  1320.  
  1321. /* read options from server resource manager */
  1322.  
  1323. read_options(side)
  1324. Side *side;
  1325. {
  1326.     char *option;
  1327.  
  1328.     option = XGetDefault(sdd(), PROGRAMNAME, "Split");
  1329.     side->split = parse_boolean(option);
  1330.     option = XGetDefault(sdd(), PROGRAMNAME, "Graph");
  1331.     side->graphical = parse_boolean(option);
  1332.     option = XGetDefault(sdd(), PROGRAMNAME, "DisplayMode");
  1333.     if (option)
  1334.         side->showmode = atoi(option) % 4;
  1335.     option = XGetDefault(sdd(), PROGRAMNAME, "Inverse");
  1336.     side->bonw = parse_boolean(option);
  1337.     option = XGetDefault(sdd(), PROGRAMNAME, "Monochrome");
  1338.     side->monochrome = parse_boolean(option);
  1339.     option = XGetDefault(sdd(), PROGRAMNAME, "InstallCmap");
  1340.     side->InstallCmap = parse_boolean(option);
  1341.     option = XGetDefault(sdd(), PROGRAMNAME, "NoticeLines");
  1342.     if (option)
  1343.         side->nh = atoi(option);
  1344.     option = XGetDefault(sdd(), PROGRAMNAME, "MapWidth");
  1345.     if (option) {
  1346.     side->vw = atoi(option);
  1347.         side->vw = min( max(side->vw, MINWIDTH), world.width);
  1348.     }
  1349.     option = XGetDefault(sdd(), PROGRAMNAME, "MapHeight");
  1350.     if (option) {
  1351.     side->vh = atoi(option);
  1352.         side->vh = min( max(side->vh, MINHEIGHT), world.height);
  1353.     }
  1354. }
  1355.  
  1356. /* parse a boolean string */
  1357. int
  1358. parse_boolean(string)
  1359. char *string;
  1360. {
  1361.     if (string == 0)
  1362.         return 0;
  1363.     if (strcmp(string, "yes") == 0 ||
  1364.         strcmp(string, "on") == 0 ||
  1365.         strcmp(string, "true") == 0)
  1366.             return 1;
  1367.     else
  1368.             return 0;
  1369. }
  1370.  
  1371. init_cmaps(side)
  1372. Side *side;
  1373. {
  1374.     int i;
  1375.     unsigned long black, white;
  1376.     unsigned long *pixels;
  1377.     XColor color_def, rgb_def;
  1378.     Visual *visual;
  1379.  
  1380.     side->cmap = DefaultColormap(sdd(), DefaultScreen(sdd()));
  1381.     if (check_colors(side)) {
  1382.             if (Debug) printf("xconq: using default colormap\n");
  1383.         return TRUE;    /* use default colormap */
  1384.     }
  1385.  
  1386.     if (Debug) printf("xconq: making new colormap\n");
  1387.     visual = DefaultVisual(sdd(),DefaultScreen(sdd()));
  1388.     side->cmap = XCreateColormap(sdd(), DefaultRootWindow(sdd()),
  1389.          visual, AllocNone);
  1390.  
  1391.     pixels = (unsigned long *)
  1392.         malloc( sizeof(unsigned long) * visual->map_entries);
  1393.     XAllocColorCells( sdd(), side->cmap, FALSE, 0, 0,
  1394.         pixels, visual->map_entries);
  1395.     white = WhitePixel(sdd(), DefaultScreen(sdd()));
  1396.         black =    BlackPixel(sdd(), DefaultScreen(sdd()));
  1397.     XStoreNamedColor(sdd(), side->cmap, "white", white,
  1398.         DoRed | DoGreen | DoBlue);
  1399.     XStoreNamedColor(sdd(), side->cmap, "black", black,
  1400.         DoRed | DoGreen | DoBlue);
  1401.  
  1402.     for( i=0; i < visual->map_entries; i++) {
  1403.         if (i == black || i == white)
  1404.         continue;
  1405.         *pixels = i;
  1406.         XFreeColors(sdd(), side->cmap, pixels, 1,  0);
  1407.     }
  1408.     free(pixels);
  1409.  
  1410.     return TRUE;
  1411.  
  1412. }
  1413.  
  1414.  
  1415. check_colors(side)
  1416. Side *side;
  1417. {
  1418.     int i;
  1419.     long colors[MAX_COLORS];
  1420.     long planes;
  1421.  
  1422.     for(i=MAX_COLORS; i>=MIN_COLORS; i--) {
  1423.         if (XAllocColorCells(sdd(), side->cmap, FALSE, &planes, 0,
  1424.             colors, i))
  1425.         break;
  1426.     }
  1427.     if (i >= MIN_COLORS) {
  1428.         XFreeColors(sdd(), side->cmap, colors, i, 0);
  1429.         return i;
  1430.     }
  1431.     else {
  1432.         return 0;
  1433.     }
  1434. }
  1435.  
  1436. /* Completely redo a screen, making no assumptions about appearance. */
  1437. /* This one is used frequently, especially when a window is exposed. */
  1438.  
  1439. redraw(side)
  1440. Side *side;
  1441. {
  1442.     XEvent report;
  1443.  
  1444.     if (active_display(side)) {
  1445.     report.xexpose.type = Expose;
  1446.     report.xexpose.display = sdd();
  1447.     report.xexpose.window = side->main;
  1448.     report.xexpose.x = report.xexpose.y =
  1449.         report.xexpose.width = report.xexpose.height = 1;
  1450.     expose(side,&report,side->main);
  1451.     expose(side,&report,side->map);
  1452.     expose(side,&report,side->world);
  1453.     expose(side,&report,side->state);
  1454.     expose(side,&report,side->msg);
  1455.     expose(side,&report,side->info);
  1456.     expose(side,&report,side->prompt);
  1457.     expose(side,&report,side->sides);
  1458.     expose(side,&report,side->timemode);
  1459.     expose(side,&report,side->clock);
  1460.     expose(side,&report,side->help);
  1461.     flush_output(side);
  1462.     flush_input(side);
  1463.     }
  1464. }
  1465.  
  1466. static
  1467. expose(side,event,window)
  1468. Side *side;
  1469. XEvent *event;
  1470. Window window;
  1471. {
  1472.     int cc;
  1473.     event->xexpose.window = window;
  1474.     cc = XSendEvent(sdd(),window,False,ExposureMask,event);
  1475. }
  1476.  
  1477. add_font_path(side,newelement)
  1478. Side *side;
  1479. char *newelement;
  1480. {
  1481.     char **fontpath, **newpath;
  1482.     int i,npaths;
  1483.  
  1484.     fontpath = XGetFontPath(sdd(), &npaths);
  1485.     newpath = (char **) malloc((npaths+1) * (sizeof(char *)));
  1486.     for(i=0;i<npaths;i++) {
  1487.         newpath[i] = fontpath[i];
  1488.     }
  1489.     newpath[i] = newelement;
  1490.     XSetFontPath(sdd(),newpath,npaths+1);
  1491.     free(newpath);
  1492.     if (fontpath)
  1493.         XFreeFontPath(fontpath);
  1494. }
  1495.